/**
 @file sys_usw_nexthop_aps.c

 @date 2020-02-25

 @version v2.0

 The file contains all aps related function
*/

/****************************************************************************
*
* Header Files
*
****************************************************************************/
#include "ctc_const.h"
#include "ctc_error.h"
#include "sys_usw_chip.h"
#include "sys_usw_nexthop_api.h"
#include "sys_usw_nexthop.h"
#include "sys_usw_nexthop_hw.h"
#include "sys_usw_wb_nh.h"
#include "sys_usw_register.h"
#include "sys_usw_aps.h"

#include "drv_api.h"

/****************************************************************************
*
* Global and Declaration
*
*****************************************************************************/
#define SYS_NH_APS_MAX_MEM_NUM 2

int32
_sys_usw_nh_aps_add_dsfwd(uint8 lchip, sys_nh_info_com_t* p_com_db, uint8 is_dsfwd1);

int32
sys_usw_nh_update_aps_by_nh(uint8 lchip, uint32 aps_nhid, uint32 mem_nhid)
{
    sys_aps_bind_nh_param_t bind_param;
    sys_nh_info_dsnh_t nh_info;
    sys_nh_info_com_t* p_nh_com_info = NULL;
    sys_nh_info_aps_t* p_nhdb = NULL;
    uint8 loop, loop_cnt;
    uint8 gchip = 0;
    uint8 arp_num = 0;

    sal_memset(&bind_param, 0, sizeof(bind_param));
    sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));

    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, aps_nhid, (sys_nh_info_com_t**)&p_nh_com_info));
    if (SYS_NH_TYPE_APS != p_nh_com_info->hdr.nh_entry_type)
    {
        return CTC_E_NONE;
    }
    CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, mem_nhid, &nh_info));
    p_nhdb = (sys_nh_info_aps_t*)p_nh_com_info;

    if ((mem_nhid != p_nhdb->w_nexthop_id) && (mem_nhid != p_nhdb->p_nexthop_id))
    {
        return CTC_E_NONE;
    }
    bind_param.working_path = (mem_nhid == p_nhdb->w_nexthop_id);
    loop_cnt = (p_nhdb->w_nexthop_id == p_nhdb->p_nexthop_id)?2:1;
    sys_usw_get_gchip_id( lchip,  &gchip);
    nh_info.dsnh_offset = (SYS_USW_DROP_NH_OFFSET == nh_info.dsnh_offset)? 0 : nh_info.dsnh_offset;
    for (loop = 0; loop < loop_cnt; loop++)
    {
      bind_param.dsnh_offset = nh_info.dsnh_offset;
      bind_param.nh_id = aps_nhid;
      bind_param.next_aps_en = nh_info.aps_en || nh_info.oam_aps_en;
      if(nh_info.use_destmap_profile && (!bind_param.next_aps_en))
      {
          bind_param.dest_id  = (nh_info.dest_map & 0xFFFF);
          bind_param.destmap_profile = 1;
      }
      else
      {
          bind_param.destmap_profile = 0;
         bind_param.dest_id  =  nh_info.drop_pkt ? CTC_MAP_LPORT_TO_GPORT(gchip, SYS_RSV_PORT_DROP_ID):nh_info.gport;
      }
      bind_param.destmap_profile = nh_info.use_destmap_profile;
      bind_param.different_nh =  1;
      bind_param.p_nexthop_en =  bind_param.different_nh;
      bind_param.assign_port = p_nhdb->assign_port;
      bind_param.is_8w = CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
      bind_param.bypass_igr_edit = nh_info.bypass_igr_edit;
     /* no need do rollback process*/
      CTC_ERROR_RETURN(sys_usw_aps_bind_nexthop(lchip, p_nhdb->aps_group_id, &bind_param));
      bind_param.working_path = !bind_param.working_path ;
   }

    if (mem_nhid == p_nhdb->w_nexthop_id)
    {
        p_nh_com_info->hdr.dsnh_offset = nh_info.dsnh_offset;
        if (nh_info.nexthop_ext)
        {
            CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
        }
        else
        {
            CTC_UNSET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
        }
        sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));
        _sys_usw_nh_get_nhinfo(lchip, aps_nhid, &nh_info);

        if (CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD))
        {
            CTC_ERROR_RETURN(_sys_usw_nh_aps_add_dsfwd(lchip, p_nh_com_info, 0));
        }
    }

    for (loop = 0; loop < 2; loop++)
    {
        uint32 tmp_nhid = 0;
        tmp_nhid = loop? p_nhdb->p_nexthop_id : p_nhdb->w_nexthop_id;
        CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, tmp_nhid, &nh_info));
        if (nh_info.use_destmap_profile)
        {
            arp_num++;
        }
    }
    p_nhdb->arp_num = arp_num;

    return CTC_E_NONE;
}

int32
_sys_usw_nh_aps_update_ref_list(uint8 lchip, sys_nh_info_aps_t* p_nhdb, sys_nh_info_com_t* p_nh_info, uint8 is_del)
{
    sys_nh_ref_list_node_t* p_curr = NULL;
    sys_nh_ref_list_node_t* p_nh_ref_list_node = NULL;
    uint8 find_flag = 0;
    sys_nh_ref_list_node_t* p_prev = NULL;
    sys_nh_info_ext_t* p_nhinfo_ext = NULL;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_ext_by_nhid(lchip, p_nh_info->hdr.nh_id, &p_nhinfo_ext, is_del? 0 : 1));
    if (NULL == p_nhinfo_ext)
    {
        return CTC_E_NONE;
    }
    p_curr = p_nhinfo_ext->aps_list;
    while (p_curr)
    {
        if ((sys_nh_info_aps_t*)p_curr->p_ref_nhinfo == p_nhdb)
        {
            find_flag = 1;
            break;
        }
        p_prev = p_curr;
        p_curr = p_curr->p_next;
    }

    if (find_flag == 0 && !is_del)
    {
        p_nh_ref_list_node = (sys_nh_ref_list_node_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_ref_list_node_t));
        if (p_nh_ref_list_node == NULL)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
            return CTC_E_NO_MEMORY;

        }
        p_nh_ref_list_node->p_ref_nhinfo = (sys_nh_info_com_t*)p_nhdb;
        p_nh_ref_list_node->p_next = p_nhinfo_ext->aps_list;
        p_nhinfo_ext->aps_list = p_nh_ref_list_node;
    }
    else if (find_flag && is_del)
    {
        if (p_prev == NULL)
        {
            p_nhinfo_ext->aps_list = p_curr->p_next;
        }
        else
        {
            p_prev->p_next = p_curr->p_next;
        }
        mem_free(p_curr);
        CTC_ERROR_RETURN(sys_usw_nh_free_nhinfo_ext_by_nhid(lchip, p_nh_info->hdr.nh_id));
    }
    return CTC_E_NONE;
}

int32
_sys_usw_nh_aps_add_dsfwd(uint8 lchip, sys_nh_info_com_t* p_com_db, uint8 is_dsfwd1)
{
    sys_nh_param_dsfwd_t dsfwd_param;
    sys_nh_info_aps_t* p_nhinfo = (sys_nh_info_aps_t*)(p_com_db);

    sal_memset(&dsfwd_param, 0, sizeof(sys_nh_param_dsfwd_t));
    dsfwd_param.nexthop_ext   = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
    dsfwd_param.dsnh_offset   = p_nhinfo->hdr.dsnh_offset;
    dsfwd_param.dsfwd_offset  = p_nhinfo->hdr.dsfwd_offset;
    dsfwd_param.is_egress_edit =  CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
    dsfwd_param.dest_id = p_nhinfo->aps_group_id;
    dsfwd_param.aps_type = CTC_APS_BRIDGE;
    if(p_nhinfo->aps_xcon_met)
     {
          dsfwd_param.aps_type = 0;
          dsfwd_param.is_mcast = 1;
          sys_usw_aps_get_met( lchip, p_nhinfo->aps_group_id ,&dsfwd_param.dest_id, NULL);
     }
    CTC_ERROR_RETURN(_sys_usw_nh_add_dsfwd(lchip, p_com_db, &dsfwd_param, is_dsfwd1));
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_APS, 1);

    return CTC_E_NONE;
}

int32
_sys_usw_nh_update_aps_fwd_attr(uint8 lchip, sys_nh_info_com_t* p_com_db, sys_nh_param_com_t* p_com_nh_param)
{
    sys_nh_param_aps_t* p_nh_aps;
    sys_nh_info_aps_t* p_nhdb = NULL;
    ctc_nh_aps_param_t* p_nh_param = NULL;
    int32 ret = 0;
    uint8  gchip = 0;
    uint8 loop = 0,loop_cnt = 0;
    sys_nh_info_dsnh_t nh_info;
    sys_nh_info_com_t* p_nh_com_info = NULL;
    uint8 arp_num = 0;
    uint8 work_bypass_flag = 0;
    uint8 use_8w = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    p_nh_aps = (sys_nh_param_aps_t*)p_com_nh_param;
    p_nhdb    = (sys_nh_info_aps_t*)p_com_db;
    p_nh_param = p_nh_aps->p_aps_param;

    loop_cnt =(p_nh_param->p_nhid != p_nh_param->w_nhid)?2:1;
    for (loop = 0; loop < loop_cnt; loop++)
    {
        sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));
        CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, (loop?p_nh_param->p_nhid:p_nh_param->w_nhid), &nh_info));
        if (nh_info.nh_entry_type == SYS_NH_TYPE_ECMP ||
            nh_info.nh_entry_type == SYS_NH_TYPE_APS  || (nh_info.nh_entry_type == SYS_NH_TYPE_MPLS && nh_info.pw_aps_en) ||
            (nh_info.nh_entry_type != SYS_NH_TYPE_MPLS && nh_info.nh_entry_type != SYS_NH_TYPE_SRV6 && nh_info.aps_en))
        {
            return CTC_E_INVALID_PARAM;
        }
        if(!DRV_FROM_AT(lchip))
        {
        if (!loop)
        {
            work_bypass_flag = nh_info.bypass_igr_edit;
            use_8w = nh_info.nexthop_ext;
        }
        else if (work_bypass_flag != nh_info.bypass_igr_edit)
        {
            return CTC_E_INVALID_PARAM;
        }
        }
    }
    if (work_bypass_flag)
    {
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
    }
    if (p_nhdb->w_nexthop_id)
    {
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, p_nhdb->w_nexthop_id, (sys_nh_info_com_t**)&p_nh_com_info));
        CTC_ERROR_RETURN(_sys_usw_nh_aps_update_ref_list(lchip, p_nhdb, p_nh_com_info, 1));
    }

    if (p_nhdb->p_nexthop_id)
    {
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip,  p_nhdb->p_nexthop_id, (sys_nh_info_com_t**)&p_nh_com_info));
        CTC_ERROR_RETURN(_sys_usw_nh_aps_update_ref_list(lchip, p_nhdb, p_nh_com_info, 1));
    }

    sys_usw_get_gchip_id( lchip,  &gchip);
    for (loop = 0; loop < SYS_NH_APS_MAX_MEM_NUM; loop++)
    {
        sys_nh_info_com_t* p_nh_com_info = NULL;
        sys_aps_bind_nh_param_t bind_param;
        sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));
        _sys_usw_nh_get_nhinfo(lchip, loop?p_nh_param->p_nhid:p_nh_param->w_nhid, &nh_info);
        sal_memset(&bind_param, 0, sizeof(bind_param));
        bind_param.working_path = loop?0:1;
        nh_info.dsnh_offset = (SYS_USW_DROP_NH_OFFSET == nh_info.dsnh_offset)? 0 : nh_info.dsnh_offset;
        bind_param.dsnh_offset = nh_info.dsnh_offset;
        p_nhdb->hdr.dsnh_offset = loop ? p_nhdb->hdr.dsnh_offset:nh_info.dsnh_offset;
        bind_param.nh_id = p_nhdb->hdr.nh_id;
        bind_param.next_aps_en = nh_info.aps_en || nh_info.oam_aps_en;
        bind_param.is_mcast = nh_info.is_mcast;
        if(nh_info.use_destmap_profile && (!bind_param.next_aps_en))
        {
            bind_param.dest_id  = (nh_info.dest_map & 0xFFFF);
            bind_param.destmap_profile = 1;
        }
        else
        {
           bind_param.dest_id  =  nh_info.drop_pkt ? CTC_MAP_LPORT_TO_GPORT(gchip, SYS_RSV_PORT_DROP_ID):nh_info.gport;
        }
        if (nh_info.use_destmap_profile)
        {
            arp_num++;
        }
        bind_param.different_nh = CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_SHARE_DSNH)? 0 : 1;
        bind_param.is_8w = CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
        bind_param.bypass_igr_edit = nh_info.bypass_igr_edit;
        bind_param.p_nexthop_en = bind_param.different_nh;
        bind_param.assign_port = CTC_FLAG_ISSET(p_nh_param->flag, CTC_APS_NH_FLAG_ASSIGN_PORT)?1:0;
        CTC_ERROR_RETURN(sys_usw_aps_bind_nexthop(lchip, p_nh_param->aps_group_id, &bind_param));
        p_nhdb->aps_xcon_met = bind_param.aps_use_mcast;
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, loop?p_nh_param->p_nhid:p_nh_param->w_nhid, (sys_nh_info_com_t**)&p_nh_com_info));
        CTC_ERROR_RETURN(_sys_usw_nh_aps_update_ref_list(lchip, p_nhdb, p_nh_com_info, 0));
    }
    p_nhdb->w_nexthop_id = p_nh_param->w_nhid;
    p_nhdb->p_nexthop_id = p_nh_param->p_nhid;
    p_nhdb->aps_group_id = p_nh_param->aps_group_id;
    p_nhdb->assign_port = CTC_FLAG_ISSET(p_nh_param->flag, CTC_APS_NH_FLAG_ASSIGN_PORT)?1:0;
    p_nhdb->hdr.nh_entry_type = SYS_NH_TYPE_APS;
    p_nhdb->arp_num = arp_num;
    if (use_8w)
    {
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
    }
    else
    {
        CTC_UNSET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
    }

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "p_nhdb->aps_group_id:%u, p_nhdb->assign_port:%u, p_nhdb->arp_num:%u\n", p_nhdb->aps_group_id,
        p_nhdb->assign_port, p_nhdb->arp_num);

    CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN);
    if (p_nh_aps->hdr.have_dsfwd)
    {
        CTC_ERROR_RETURN(_sys_usw_nh_aps_add_dsfwd(lchip, p_com_db, 0));
    }
    if (DRV_FROM_AT(lchip) && p_nh_aps->hdr.have_dsfwd1)
    {
        CTC_ERROR_RETURN(_sys_usw_nh_aps_add_dsfwd(lchip, p_com_db, 1));
    }

    if ((p_nhdb->aps_xcon_met) && (!DRV_FROM_TMM(lchip)))
    {
        bool protect_en = FALSE;
        CTC_ERROR_RETURN(sys_usw_aps_get_protection(lchip, p_nhdb->aps_group_id, &protect_en));
        CTC_ERROR_RETURN(_sys_usw_nh_set_pw_working_path(lchip, !protect_en, p_nhdb));
    }
    
    return ret;
}

int32
_sys_usw_nh_update_ref_list(uint8 lchip, sys_nh_tunnel_ref_list_node_t**  p_ref_list, void* p_aps_tunnel, uint8 is_del)/*for mpls tunnel or srh edit*/
{
    sys_nh_tunnel_ref_list_node_t* p_curr = NULL;
    sys_nh_tunnel_ref_list_node_t* p_tunnel_list_node = NULL;
    uint8 find_flag = 0;
    sys_nh_tunnel_ref_list_node_t* p_prev = NULL;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    p_curr = *p_ref_list;
    while (p_curr)
    {
        if (p_curr->p_ref_node == p_aps_tunnel)
        {
            find_flag = 1;
            break;
        }
        p_prev = p_curr;
        p_curr = p_curr->p_next;
    }

    if (find_flag == 0 && !is_del)
    {
        p_tunnel_list_node = (sys_nh_tunnel_ref_list_node_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_tunnel_ref_list_node_t));
        if (p_tunnel_list_node == NULL)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
            return CTC_E_NO_MEMORY;
        }
        p_tunnel_list_node->p_ref_node = p_aps_tunnel;
        p_tunnel_list_node->p_next = *p_ref_list;
        *p_ref_list = p_tunnel_list_node;
    }
    else if (find_flag && is_del)
    {
        if (p_prev == NULL)
        {
            *p_ref_list = p_curr->p_next;
        }
        else
        {
            p_prev->p_next = p_curr->p_next;
        }
        mem_free(p_curr);
    }

    return CTC_E_NONE;
}

int32
_sys_usw_nh_update_tunnel_aps(uint8 lchip, uint16 tunnel_id, ctc_nh_aps_param_t* p_para, uint8 is_update)
{
    int32 ret = 0;
    sys_nh_db_mpls_tunnel_t* p_w_tunnel = NULL;
    sys_nh_db_mpls_tunnel_t* p_p_tunnel = NULL;
    sys_nh_db_mpls_tunnel_t* p_aps_tunnel = NULL;
    sys_aps_bind_nh_param_t bind_param;
    sys_nh_db_mpls_tunnel_t* p_tmp_tunnel = NULL;
    uint8 loop = 0;
    sys_nh_db_mpls_tunnel_t* old_tunnel_w = NULL;
    sys_nh_db_mpls_tunnel_t* old_tunnel_p = NULL;

    /*check mpls tunnel exist*/
    CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, p_para->w_nhid, &p_w_tunnel));
    CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, p_para->p_nhid, &p_p_tunnel));
    if (!p_w_tunnel || !p_p_tunnel)
    {
        return CTC_E_NOT_EXIST;
    }
    if (CTC_FLAG_ISSET(p_p_tunnel->flag, SYS_NH_MPLS_TUNNEL_FLAG_APS))
    {
        return CTC_E_INVALID_CONFIG;
    }
    if (!is_update)
    {
        p_aps_tunnel  = (sys_nh_db_mpls_tunnel_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_db_mpls_tunnel_t));
        if (!p_aps_tunnel)
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(p_aps_tunnel, 0, sizeof(sys_nh_db_mpls_tunnel_t));

        p_aps_tunnel->pd  = (sys_nh_info_mpls_tnl_pdata_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_info_mpls_tnl_pdata_t));
        if (!p_aps_tunnel->pd)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
            ret = CTC_E_NO_MEMORY;
            goto error_proc;
        }
        sal_memset(p_aps_tunnel->pd, 0, sizeof(sys_nh_info_mpls_tnl_pdata_t));
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, tunnel_id, &p_aps_tunnel));
        if (!p_aps_tunnel)
        {
            return CTC_E_NOT_EXIST;
        }

        if (p_para->w_nhid != p_aps_tunnel->l3ifid)
        {
            CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, p_aps_tunnel->l3ifid, &old_tunnel_w));
        }

        if (p_para->p_nhid != p_aps_tunnel->p_l3ifid)
        {
            CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, p_aps_tunnel->p_l3ifid, &old_tunnel_p));
        }
    }

    for (loop = 0; loop < SYS_NH_APS_MAX_MEM_NUM; loop++)
    {
        sal_memset(&bind_param, 0, sizeof(sys_aps_bind_nh_param_t));
        p_tmp_tunnel = loop?p_p_tunnel:p_w_tunnel;
        if (!p_tmp_tunnel->label_num)
        {
            bind_param.edit_ptr = p_tmp_tunnel->l2edit_offset;
            bind_param.edit_ptr_type = 0;
            bind_param.edit_ptr_location = 1;
            if (bind_param.edit_ptr >= MCHIP_CAP(SYS_CAP_NH_OUTER_L2_EDIT_NUM))
            {
               /*use spme resource to edit ARP*/
                   bind_param.edit_ptr_type = 1;
                   bind_param.edit_ptr = bind_param.edit_ptr - MCHIP_CAP(SYS_CAP_NH_OUTER_L2_EDIT_NUM);
                   bind_param.edit_ptr |= (DRV_FROM_TMM(lchip)? (1 << 11) : (1 << 10));
            }
        }
        else
        {
            bind_param.edit_ptr = p_tmp_tunnel->lsp_offset;
            bind_param.edit_ptr_type = 1;
            bind_param.edit_ptr_location = CTC_FLAG_ISSET(p_tmp_tunnel->flag, SYS_NH_MPLS_TUNNEL_FLAG_IS_SPME)?1:0;
        }
        bind_param.working_path = !loop?1:0;
        bind_param.edit_ptr_valid =1;
        bind_param.is_tunnel = 1;
        bind_param.nh_id = tunnel_id;
        bind_param.l3if_id = p_tmp_tunnel->l3ifid;

        if (!loop)
        {
            p_aps_tunnel->arp_id = p_tmp_tunnel->arp_id;
        }

        if (p_tmp_tunnel->arp_id && (0 == p_tmp_tunnel->sr_loop_num))
        {
            sys_nh_db_arp_t* p_arp = NULL;
            p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_tmp_tunnel->arp_id));
            if(p_arp)
            {
               bind_param.destmap_profile = 1;
               bind_param.dest_id = p_arp->destmap_profile;
            }
        }
        else
        {
            bind_param.dest_id = p_tmp_tunnel->gport;
        }
        CTC_ERROR_GOTO(sys_usw_aps_bind_nexthop(lchip, p_para->aps_group_id, &bind_param), ret, error_proc);
    }

    p_aps_tunnel->tunnel_id = tunnel_id;
    p_aps_tunnel->gport = p_para->aps_group_id;
    p_aps_tunnel->l3ifid = p_para->w_nhid;
    p_aps_tunnel->p_l3ifid = p_para->p_nhid;
    CTC_SET_FLAG(p_aps_tunnel->flag, SYS_NH_MPLS_TUNNEL_FLAG_APS);

    if (!is_update)
    {
        if (FALSE == ctc_vector_add(g_usw_nh_master[lchip]->tunnel_id_vec, tunnel_id, p_aps_tunnel))
        {
    		ret = CTC_E_NO_MEMORY;
            goto error_proc;
        }
    }

    CTC_ERROR_GOTO(_sys_usw_nh_update_ref_list(lchip, &(p_w_tunnel->pd->p_tunnel_list), p_aps_tunnel, 0), ret, error_proc1);
    CTC_ERROR_GOTO(_sys_usw_nh_update_ref_list(lchip, &(p_p_tunnel->pd->p_tunnel_list), p_aps_tunnel, 0), ret, error_proc1);
    if (is_update && old_tunnel_w)
    {
        CTC_ERROR_GOTO(_sys_usw_nh_update_ref_list(lchip, &(old_tunnel_w->pd->p_tunnel_list), p_aps_tunnel, 1), ret, error_proc1);
    }
    if (is_update && old_tunnel_p)
    {
        CTC_ERROR_GOTO(_sys_usw_nh_update_ref_list(lchip, &(old_tunnel_p->pd->p_tunnel_list), p_aps_tunnel, 1), ret, error_proc1);
    }
    return CTC_E_NONE;
error_proc1:
    if (!is_update)
    {
        ctc_vector_del(g_usw_nh_master[lchip]->tunnel_id_vec, tunnel_id);
    }
error_proc:

    if (!is_update && p_aps_tunnel)
    {
        if(p_aps_tunnel->pd)
        {
            mem_free(p_aps_tunnel->pd);
        }

        mem_free(p_aps_tunnel);
    }

    return ret;
}


int32
_sys_usw_nh_update_srh_aps(uint8 lchip, uint32 srh_id, ctc_nh_aps_param_t* p_para, uint8 is_update)
{
    int32 ret = 0;
    sys_nh_db_srh_t* p_w_srh = NULL;
    sys_nh_db_srh_t* p_p_srh = NULL;
    sys_nh_db_srh_t* p_aps_srh = NULL;
    sys_aps_bind_nh_param_t bind_param;
    sys_nh_db_srh_t* p_tmp_srh = NULL;
    uint8 loop = 0;
    sys_nh_db_srh_t* old_srh_w = NULL;
    sys_nh_db_srh_t* old_srh_p = NULL;
    sys_nh_db_arp_t* p_arp = NULL;

    /*check mpls tunnel exist*/
    CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, p_para->w_nhid, &p_w_srh));
    CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, p_para->p_nhid, &p_p_srh));
    if (!p_w_srh || !p_p_srh)
    {
        return CTC_E_NOT_EXIST;
    }
    if (CTC_FLAG_ISSET(p_w_srh->flag, SYS_NH_SRH_FLAG_APS) || CTC_FLAG_ISSET(p_p_srh->flag, SYS_NH_SRH_FLAG_APS))
    {
        return CTC_E_INVALID_CONFIG;
    }
    if (!p_w_srh->num || !p_p_srh->num)
    {
        return CTC_E_INVALID_CONFIG;
    }

    if (!is_update)
    {
        p_aps_srh  = (sys_nh_db_srh_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_db_srh_t));
        if (!p_aps_srh)
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(p_aps_srh, 0, sizeof(sys_nh_db_srh_t));
        p_aps_srh->pd = (sys_nh_db_srh_pdata_t*)mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_db_srh_pdata_t));
        if (!p_aps_srh->pd)
        {
            ret =  CTC_E_NO_MEMORY;
            goto error_proc;
        }
        sal_memset(p_aps_srh->pd, 0, sizeof(sys_nh_db_srh_pdata_t));
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, srh_id, &p_aps_srh));
        if (!p_aps_srh)
        {
            return CTC_E_NOT_EXIST;
        }

        if (p_para->w_nhid != p_aps_srh->l3edit_ptr)
        {
            CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, p_aps_srh->l3edit_ptr, &old_srh_w));
        }

        if (p_para->p_nhid != p_aps_srh->p_srh_id)
        {
            CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, p_aps_srh->p_srh_id, &old_srh_p));
        }
    }

    for (loop = 0; loop < SYS_NH_APS_MAX_MEM_NUM; loop++)
    {
        sal_memset(&bind_param, 0, sizeof(sys_aps_bind_nh_param_t));
        p_tmp_srh = loop?p_p_srh:p_w_srh;

        p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_tmp_srh->arp_id));
        if (NULL == p_arp)
        {
            ret = CTC_E_INVALID_CONFIG;
            goto error_proc;
        }

        if (0 == p_tmp_srh->num)
        {
            bind_param.edit_ptr = p_arp->offset;
            bind_param.edit_ptr_type = 0;
            bind_param.edit_ptr_location = 1;
            if (bind_param.edit_ptr >= MCHIP_CAP(SYS_CAP_NH_OUTER_L2_EDIT_NUM))
            {
                bind_param.edit_ptr_type = 1;
                bind_param.edit_ptr = bind_param.edit_ptr - MCHIP_CAP(SYS_CAP_NH_OUTER_L2_EDIT_NUM);
                bind_param.edit_ptr |= (DRV_FROM_TMM(lchip)? (1 << 11) : (1 << 10));
            }
        }
        else
        {
            bind_param.edit_ptr = p_tmp_srh->l3edit_ptr;
            bind_param.edit_ptr_type = 1;
            bind_param.edit_ptr_location = 0;
        }

        bind_param.working_path = !loop?1:0;
        bind_param.edit_ptr_valid =1;
        bind_param.is_tunnel = 1;
        bind_param.nh_id = srh_id;

        bind_param.destmap_profile = 1;
        bind_param.dest_id = p_arp->destmap_profile;
        bind_param.l3if_id = p_arp->l3if_id;

        CTC_ERROR_GOTO(sys_usw_aps_bind_nexthop(lchip, p_para->aps_group_id, &bind_param), ret, error_proc);
    }

    p_aps_srh->srh_id = srh_id;
    p_aps_srh->arp_id = p_para->aps_group_id;
    p_aps_srh->l3edit_ptr = p_para->w_nhid;
    p_aps_srh->p_srh_id = p_para->p_nhid;
    CTC_SET_FLAG(p_aps_srh->flag, SYS_NH_SRH_FLAG_APS);

    if (!is_update)
    {
        if (FALSE == ctc_hash_insert(g_usw_nh_master[lchip]->srh_id_hash, p_aps_srh))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] No memory \n");
            ret = CTC_E_NO_MEMORY;
            goto error_proc;
        }
    }

    CTC_ERROR_GOTO(_sys_usw_nh_update_ref_list(lchip, &(p_w_srh->pd->p_srh_list), p_aps_srh, 0), ret, error_proc);
    CTC_ERROR_GOTO(_sys_usw_nh_update_ref_list(lchip, &(p_p_srh->pd->p_srh_list), p_aps_srh, 0), ret, error_proc);
    if (is_update && old_srh_w)
    {
        CTC_ERROR_RETURN(_sys_usw_nh_update_ref_list(lchip, &(old_srh_w->pd->p_srh_list), p_aps_srh, 1));
    }
    if (is_update && old_srh_p)
    {
        CTC_ERROR_RETURN(_sys_usw_nh_update_ref_list(lchip, &(old_srh_p->pd->p_srh_list), p_aps_srh, 1));
    }
    return CTC_E_NONE;
error_proc:

    if (!is_update)
    {
        if (p_aps_srh->pd)
        {
            mem_free(p_aps_srh->pd);
        }
        mem_free(p_aps_srh);
    }

    return ret;
}


#define ___SYS_APS__

int32
sys_usw_nh_create_aps_cb(uint8 lchip, sys_nh_param_com_t* p_com_nh_param, sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_aps_t* p_nh_aps;
    sys_nh_info_aps_t* p_nhdb = NULL;
    ctc_nh_aps_param_t* p_nh_param = NULL;
    ctc_aps_bridge_group_t aps_grp;
    int32 ret = 0;
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    p_nh_aps = (sys_nh_param_aps_t*)p_com_nh_param;
    p_nhdb    = (sys_nh_info_aps_t*)p_com_db;
    p_nh_param = p_nh_aps->p_aps_param;
    if (!p_nh_param->w_nhid || !p_nh_param->p_nhid)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "%s()\n", __FUNCTION__);
        return CTC_E_INVALID_CONFIG;
    }
    ret = sys_usw_aps_get_ports(lchip, p_nh_param->aps_group_id, &aps_grp);
    if (CTC_E_NOT_EXIST == ret)
    {
        return CTC_E_NOT_EXIST;
    }
   p_nhdb->aps_group_id = p_nh_param->aps_group_id;
   CTC_ERROR_RETURN(_sys_usw_nh_update_aps_fwd_attr( lchip,p_com_db, p_com_nh_param));
   return CTC_E_NONE;
}


int32
sys_usw_nh_update_aps_cb(uint8 lchip, sys_nh_info_com_t* p_com_db, sys_nh_param_com_t* p_com_nh_param)
{
    int32 ret = 0;
    sys_nh_param_aps_t* p_nh_aps;
    sys_nh_info_aps_t* p_nhdb = NULL;
    ctc_nh_aps_param_t* p_nh_param = NULL;
    uint8 old_arp_num = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    p_nh_aps = (sys_nh_param_aps_t*)p_com_nh_param;
    p_nhdb    = (sys_nh_info_aps_t*)p_com_db;
    CTC_EQUAL_CHECK(SYS_NH_TYPE_APS, p_nh_aps->hdr.nh_param_type);
    switch (p_nh_aps->hdr.change_type)
    {
    case SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR:
        p_nh_param = p_nh_aps->p_aps_param;
        if (!p_nh_param->w_nhid || !p_nh_param->p_nhid || (p_nhdb->aps_group_id != p_nh_param->aps_group_id))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "%s()\n", __FUNCTION__);
            return CTC_E_INVALID_CONFIG;
        }
        p_nh_aps->hdr.have_dsfwd  = CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD);
        p_nh_aps->hdr.have_dsfwd1  = CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD1);
        old_arp_num = p_nhdb->arp_num;
        p_nhdb->arp_num = 0;
        ret = _sys_usw_nh_update_aps_fwd_attr(lchip, p_com_db, p_com_nh_param);
        if (ret)
        {
            p_nhdb->arp_num = old_arp_num;
            return ret;
        }

        break;
    case SYS_NH_CHANGE_TYPE_ADD_DYNTBL:
        {
           SYS_NH_DSFWD_CHK(p_nhdb->hdr.nh_entry_flags, p_nh_aps->hdr.is_dsfwd1);
           CTC_ERROR_RETURN(_sys_usw_nh_aps_add_dsfwd(lchip, p_com_db, p_nh_aps->hdr.is_dsfwd1));
        }
        break;

    default:
        return CTC_E_INVALID_PARAM;
    }

    if (p_com_nh_param->hdr.p_nh_info_ext && p_com_nh_param->hdr.p_nh_info_ext->ecmp_list)
    {
        ret = (sys_usw_nh_update_ecmp_member(lchip, p_nh_aps->hdr.nhid, p_nh_aps->hdr.change_type, p_com_nh_param->hdr.p_nh_info_ext->ecmp_list));
        if (ret)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop update for ecmp fail!, ret:%d \n", ret);
        }
    }
    return ret;
}

int32
sys_usw_nh_delete_aps_cb(uint8 lchip, sys_nh_info_com_t* p_com_db, sys_nh_param_com_t* p_para)
{
    sys_aps_bind_nh_param_t aps_bind;
    sys_nh_info_aps_t* p_nhdb = NULL;
    sys_nh_info_com_t* p_nh_com_info = NULL;
    sys_nh_ref_list_node_t* p_ref_node, * p_tmp_node;
    uint8 loop = 0;
    int32 ret = CTC_E_NONE;

    p_nhdb = (sys_nh_info_aps_t*)p_com_db;

    if(p_para->hdr.p_nh_info_ext && p_para->hdr.p_nh_info_ext->ecmp_list)
    {
        sys_usw_nh_update_ecmp_member(lchip, p_com_db->hdr.nh_id, SYS_NH_CHANGE_TYPE_NH_DELETE, p_para->hdr.p_nh_info_ext->ecmp_list);
        /*1. delete all reference ecmp nh*/
        p_ref_node = p_para->hdr.p_nh_info_ext->ecmp_list;

        while (p_ref_node)
        {
            /*Remove from db*/
            p_tmp_node = p_ref_node;
            p_ref_node = p_ref_node->p_next;
            mem_free(p_tmp_node);
        }
        p_para->hdr.p_nh_info_ext->ecmp_list = NULL;
    }
    if(p_nhdb->bind_data)
    {
        mem_free(p_nhdb->bind_data);
    }
    sal_memset(&aps_bind, 0, sizeof(sys_aps_bind_nh_param_t));
    aps_bind.nh_id = p_com_db->hdr.nh_id;
    aps_bind.assign_port = p_nhdb->assign_port;
    for (loop = 0; loop < SYS_NH_APS_MAX_MEM_NUM; loop++)
    {
        aps_bind.working_path = loop?0:1;
        aps_bind.nh_id = p_com_db->hdr.nh_id;
        sys_usw_aps_unbind_nexthop(lchip, p_nhdb->aps_group_id, &aps_bind);
        ret = (sys_usw_nh_get_nhinfo_by_nhid(lchip, loop?p_nhdb->p_nexthop_id:p_nhdb->w_nexthop_id, (sys_nh_info_com_t**)&p_nh_com_info));
        if (CTC_E_NONE == ret)
        {
            _sys_usw_nh_aps_update_ref_list(lchip, p_nhdb, p_nh_com_info, 1);
        }
    }
    _sys_usw_nh_remove_dsfwd(lchip, p_com_db);

    if (CTC_FLAG_ISSET(p_com_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD))
    {
        sys_nh_param_dsfwd_t dsfwd_param;

        sal_memset(&dsfwd_param, 0, sizeof(sys_nh_param_dsfwd_t));
        dsfwd_param.dsfwd_offset = p_com_db->hdr.dsfwd_offset;
        dsfwd_param.drop_pkt = 1;
        sys_usw_nh_write_entry_dsfwd(lchip, &dsfwd_param);
        /*Free DsFwd offset*/
        sys_usw_nh_offset_free(lchip,SYS_NH_ENTRY_TYPE_FWD_HALF, 1, p_com_db->hdr.dsfwd_offset);
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_aps_cb(uint8 lchip, sys_nh_info_com_t* p_nh_db, void* p_para)
{
    sys_nh_info_aps_t* p_nh_info;
    ctc_nh_aps_param_t* p_aps_param = NULL;

    CTC_PTR_VALID_CHECK(p_para);
    p_nh_info = (sys_nh_info_aps_t*)(p_nh_db);
    p_aps_param = (ctc_nh_aps_param_t*)p_para;

    p_aps_param->aps_group_id = p_nh_info->aps_group_id;
    p_aps_param->w_nhid = p_nh_info->w_nexthop_id;
    p_aps_param->p_nhid = p_nh_info->p_nexthop_id;
    if (p_nh_info->assign_port)
    {
        CTC_SET_FLAG(p_aps_param->flag, CTC_APS_NH_FLAG_ASSIGN_PORT);
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_delete_tunnel_aps(uint8 lchip, uint16 tunnel_id)
{
    sys_nh_db_mpls_tunnel_t* p_tunnel = NULL;
    sys_aps_bind_nh_param_t aps_bind;
    uint8 loop = 0;
    sys_nh_db_mpls_tunnel_t* p_w_tunnel = NULL;
    sys_nh_db_mpls_tunnel_t* p_p_tunnel = NULL;

    CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, tunnel_id, &p_tunnel));
    if (!p_tunnel)
    {
        return CTC_E_NOT_EXIST;
    }

    if (!CTC_FLAG_ISSET(p_tunnel->flag, SYS_NH_MPLS_TUNNEL_FLAG_APS))
    {
        return CTC_E_INVALID_PARAM;
    }

    if (p_tunnel->pd->p_ref_nh_list)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Other nexthop are using already\n");
		return CTC_E_IN_USE;
    }

    CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, p_tunnel->l3ifid, &p_w_tunnel));
    CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, p_tunnel->p_l3ifid, &p_p_tunnel));
    if (!p_w_tunnel || !p_p_tunnel)
    {
        return CTC_E_NOT_EXIST;
    }

    sal_memset(&aps_bind, 0, sizeof(sys_aps_bind_nh_param_t));
    aps_bind.nh_id = tunnel_id;
    aps_bind.is_tunnel = 1;
    for (loop = 0; loop < SYS_NH_APS_MAX_MEM_NUM; loop++)
    {
        aps_bind.working_path = loop?0:1;
        sys_usw_aps_unbind_nexthop(lchip, p_tunnel->gport, &aps_bind);
    }

    _sys_usw_nh_update_ref_list(lchip, &(p_w_tunnel->pd->p_tunnel_list), p_tunnel, 1);
    _sys_usw_nh_update_ref_list(lchip, &(p_p_tunnel->pd->p_tunnel_list), p_tunnel, 1);

    ctc_vector_del(g_usw_nh_master[lchip]->tunnel_id_vec, tunnel_id);
    mem_free(p_tunnel->pd);
    mem_free(p_tunnel);

    return CTC_E_NONE;
}

int32
sys_usw_nh_create_tunnel_aps(uint8 lchip, uint16 tunnel_id, ctc_nh_aps_param_t* p_para)
{
    sys_nh_db_mpls_tunnel_t* p_tunnel = NULL;

    CTC_PTR_VALID_CHECK(p_para);

    CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, tunnel_id, &p_tunnel));
    if (p_tunnel)
    {
        return CTC_E_EXIST;
    }

    CTC_ERROR_RETURN(_sys_usw_nh_update_tunnel_aps(lchip, tunnel_id, p_para, 0));

    return CTC_E_NONE;
}

int32
sys_usw_nh_update_tunnel_aps(uint8 lchip, uint16 tunnel_id, ctc_nh_aps_param_t* p_para)
{
    sys_nh_db_mpls_tunnel_t* p_tunnel = NULL;
    sys_nh_db_mpls_tunnel_t* p_w_tunnel = NULL;
    sys_nh_db_mpls_tunnel_t* p_p_tunnel = NULL;

    CTC_PTR_VALID_CHECK(p_para);
    /*check aps exist*/
    CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, tunnel_id, &p_tunnel));
    if (!p_tunnel)
    {
        return CTC_E_NOT_EXIST;
    }

    if (p_tunnel->gport != p_para->aps_group_id || !CTC_FLAG_ISSET(p_tunnel->flag, SYS_NH_MPLS_TUNNEL_FLAG_APS))
    {
        return CTC_E_INVALID_PARAM;
    }

    CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, p_tunnel->l3ifid, &p_w_tunnel));
    CTC_ERROR_RETURN(sys_usw_nh_lkup_mpls_tunnel(lchip, p_tunnel->p_l3ifid, &p_p_tunnel));
    if (!p_w_tunnel || !p_p_tunnel)
    {
        return CTC_E_NOT_EXIST;
    }

    CTC_ERROR_RETURN(_sys_usw_nh_update_tunnel_aps(lchip, tunnel_id, p_para, 1));

    return CTC_E_NONE;
}



int32
sys_usw_nh_create_srh_aps(uint8 lchip, uint32 srh_id, ctc_nh_aps_param_t* p_para)
{
    sys_nh_db_srh_t* p_srh = NULL;

    CTC_PTR_VALID_CHECK(p_para);

    CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, srh_id, &p_srh));
    if (p_srh)
    {
        return CTC_E_EXIST;
    }

    CTC_ERROR_RETURN(_sys_usw_nh_update_srh_aps(lchip, srh_id, p_para, 0));

    return CTC_E_NONE;
}

int32
sys_usw_nh_delete_srh_aps(uint8 lchip, uint32 srh_id)
{
    sys_nh_db_srh_t* p_srh = NULL;
    sys_aps_bind_nh_param_t aps_bind;
    uint8 loop = 0;
    sys_nh_db_srh_t* p_w_srh = NULL;
    sys_nh_db_srh_t* p_p_srh = NULL;

    CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, srh_id, &p_srh));
    if (!p_srh)
    {
        return CTC_E_NOT_EXIST;
    }

    if (!CTC_FLAG_ISSET(p_srh->flag, SYS_NH_SRH_FLAG_APS))
    {
        return CTC_E_INVALID_PARAM;
    }

    if (p_srh->pd->nh_list)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Other nexthop are using already\n");
        return CTC_E_IN_USE;
    }

    CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, p_srh->l3edit_ptr, &p_w_srh));
    CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, p_srh->p_srh_id, &p_p_srh));
    if (!p_w_srh || !p_p_srh)
    {
        return CTC_E_NOT_EXIST;
    }

    sal_memset(&aps_bind, 0, sizeof(sys_aps_bind_nh_param_t));
    aps_bind.nh_id = srh_id;
    aps_bind.is_tunnel = 1;
    for (loop = 0; loop < SYS_NH_APS_MAX_MEM_NUM; loop++)
    {
        aps_bind.working_path = loop?0:1;
        sys_usw_aps_unbind_nexthop(lchip, p_srh->arp_id, &aps_bind);
    }

    _sys_usw_nh_update_ref_list(lchip, &(p_w_srh->pd->p_srh_list), p_srh, 1);
    _sys_usw_nh_update_ref_list(lchip, &(p_p_srh->pd->p_srh_list), p_srh, 1);

    ctc_hash_remove(g_usw_nh_master[lchip]->srh_id_hash, p_srh);
    mem_free(p_srh->pd);
    mem_free(p_srh);

    return CTC_E_NONE;
}

int32
sys_usw_nh_update_srh_aps(uint8 lchip, uint32 srh_id, ctc_nh_aps_param_t* p_para)
{
    sys_nh_db_srh_t* p_srh = NULL;
    sys_nh_db_srh_t* p_w_srh = NULL;
    sys_nh_db_srh_t* p_p_srh = NULL;

    CTC_PTR_VALID_CHECK(p_para);
    /*check aps exist*/
    CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, srh_id, &p_srh));
    if (!p_srh)
    {
        return CTC_E_NOT_EXIST;
    }

    if (p_srh->arp_id != p_para->aps_group_id || !CTC_FLAG_ISSET(p_srh->flag, SYS_NH_SRH_FLAG_APS))
    {
        return CTC_E_INVALID_PARAM;
    }

    CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, p_srh->l3edit_ptr, &p_w_srh));
    CTC_ERROR_RETURN(sys_usw_nh_lkup_srh_edit(lchip, p_srh->p_srh_id, &p_p_srh));
    if (!p_w_srh || !p_p_srh)
    {
        return CTC_E_NOT_EXIST;
    }

    CTC_ERROR_RETURN(_sys_usw_nh_update_srh_aps(lchip, srh_id, p_para, 1));

    return CTC_E_NONE;
}



